package net.sql;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import net.sql.config.SQLBean;
import net.sql.config.SQLConfig;
import net.sql.i.IDataRow;
import oracle.sql.CLOB;

/**
 * @author 李岩飞
 * @email eliyanfei@126.com
 * @date 2018年7月20日上午10:08:00
 */
public class SqlProcessor {
	private final SQLBean sqlBean;
	private Map<String, String> colList = new LinkedHashMap<String, String>();// 查询列信息
	private List<Object> dataList = new ArrayList<Object>();// 数据集合
	private Map<String, Object> dataKeyMap = new LinkedHashMap<String, Object>();// 数据集合

	public SqlProcessor(SQLBean sqlBean) {
		this.sqlBean = sqlBean;
	}

	/**
	 * 创建对象
	 */
	private Object createObject() {
		try {
			Object beanObj = Class.forName(sqlBean.getReturnType()).newInstance();
			return beanObj;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 列头信息
	 */
	public void header(ResultSetMetaData rsmd) {
		try {
			for (int i = 0; i < rsmd.getColumnCount(); i++) {
				colList.put(rsmd.getColumnLabel(i + 1).toUpperCase(), rsmd.getColumnLabel(i + 1).toLowerCase());
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 处理数据
	 */
	@SuppressWarnings("unchecked")
	public void process(ResultSet rs, IDataRow row) {
		try {
			Object beanObj = createObject();
			if (!sqlBean.isBean()) {// Map对象
				Map<String, Object> dataMap = (Map<String, Object>) beanObj;
				for (String col : colList.keySet()) {
					Object obj = rs.getObject(colList.get(col));
					if (obj instanceof CLOB) {
						dataMap.put(col, rs.getString(colList.get(col)));
					} else {
						dataMap.put(col, obj);
					}
				}
				if (row != null) {
					row.callback(dataMap);
				}
				dataList.add(dataMap);
			} else {
				Map<String, Object> dataMap = new HashMap<String, Object>();
				for (String col : colList.keySet()) {
					Object obj = rs.getObject(colList.get(col));
					if (obj instanceof CLOB) {
						dataMap.put(col, rs.getString(colList.get(col)));
					} else {
						dataMap.put(col, obj);
					}
				}
				if (row != null) {
					row.callback(dataMap);
				}
				transMap2HiberanteBean(dataMap, beanObj);
				dataList.add(beanObj);
			}
		} catch (Exception e) {
			e.printStackTrace();
			SQLConfig.getSqlConfig().printError(e, "");
		}
	}

	public void processNoCache(ResultSet rs, IDataRow row) {
		try {
			Object beanObj = createObject();
			Map<String, Object> dataMap = (Map<String, Object>) beanObj;
			for (String col : colList.keySet()) {
				Object obj = rs.getObject(colList.get(col));
				if (obj instanceof CLOB) {
					dataMap.put(col, rs.getString(colList.get(col)));
				} else {
					dataMap.put(col, obj);
				}
			}
			if (row != null) {
				row.callback(dataMap);
			}
		} catch (Exception e) {
			e.printStackTrace();
			SQLConfig.getSqlConfig().printError(e, "");
		}
	}

	@SuppressWarnings("unchecked")
	public void processKey(ResultSet rs, IDataRow row) {
		try {
			Object beanObj = createObject();
			if (!sqlBean.isBean()) {// Map对象
				Map<String, Object> dataMap = (Map<String, Object>) beanObj;
				for (String col : colList.keySet()) {
					Object obj = rs.getObject(col);
					if (obj instanceof CLOB) {
						dataMap.put(col, rs.getString(colList.get(col)));
					} else {
						dataMap.put(col, obj);
					}
				}
				if (row != null) {
					row.callback(dataMap);
				}
				dataKeyMap.put(String.valueOf(dataMap.get("KEYID")), dataMap);
			} else {
				Map<String, Object> dataMap = new HashMap<String, Object>();
				for (String col : colList.keySet()) {
					Object obj = rs.getObject(col);
					if (obj instanceof CLOB) {
						dataMap.put(col, rs.getString(colList.get(col)));
					} else {
						dataMap.put(col, obj);
					}
				}
				if (row != null) {
					row.callback(dataMap);
				}
				transMap2HiberanteBean(dataMap, beanObj);
				dataList.add(beanObj);
				dataKeyMap.put(String.valueOf(dataMap.get("KEYID")), beanObj);
			}
		} catch (Exception e) {
			e.printStackTrace();
			SQLConfig.getSqlConfig().printError(e, "");
		}
	}

	public void transMap2HiberanteBean(Map<String, Object> map, Object obj) {
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

			for (PropertyDescriptor property : propertyDescriptors) {
				String key = property.getName();
				// 将key中大写字符转为_大写
				key = underscoreName(key).toUpperCase();
				if (map.containsKey(key)) {
					Object value = map.get(key);
					if (value != null) {
						// 得到property对应的setter方法
						Method setter = property.getWriteMethod();
						setter.invoke(obj, getRealValue(value, property.getPropertyType()));
					}
				}
			}
		} catch (Exception e) {
			System.out.println("transMap2Bean Error " + e);
			SQLConfig.getSqlConfig().printError(e, "");
		}
		return;

	}

	public Object getRealValue(Object value, Class<?> type) {
		if (value instanceof BigDecimal) {
			if (type == Integer.class)
				return ((BigDecimal) value).intValue();
			else if (type == Float.class)
				return ((BigDecimal) value).floatValue();
			else if (type == Double.class)
				return ((BigDecimal) value).doubleValue();
			else if (type == Short.class)
				return ((BigDecimal) value).shortValue();
			else if (type == Long.class)
				return ((BigDecimal) value).longValue();
		}
		return value;
	}

	String underscoreName(String name) {
		StringBuilder result = new StringBuilder();
		if ((name != null) && (name.length() > 0)) {
			result.append(name.substring(0, 1).toLowerCase());
			for (int i = 1; i < name.length(); ++i) {
				String s = name.substring(i, i + 1);
				if (s.equals(s.toUpperCase())) {
					result.append("_");
					result.append(s.toLowerCase());
				} else {
					result.append(s);
				}
			}
		}
		return result.toString();
	}

	/**
	 * 数据结果
	 */
	public List<Object> result() {
		return dataList;
	}

	public Map<String, Object> resultKey() {
		return dataKeyMap;
	}

}
